/*
 * $Id$
 *
 * Copyright 2006- Revolution Health Group.  All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Revolution Health Group.  (Confidential Information).
 * You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license 
 * agreement you entered into with Revolution Health Group.
 *
 */
package org.javason.jsonrpc;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import net.sf.json.*;
import net.sf.json.test.JSONAssert;
import net.sf.json.util.JSONUtils;

import org.javason.json.BeanToJsonSerializer;
import org.javason.jsonrpc.JsonBean.TEST_TYPE;
import org.javason.jsonrpc.impl.DateConverter;
import org.javason.jsonrpc.impl.JsonRpcOperationInvoker;
import org.javason.jsonrpc.impl.JsonRpcService;

import junit.framework.TestCase;

public class TestSerialization extends TestCase {

	public void testRequestFactory() throws JSONException {
		JSONObject req = JsonRpcRequestFactory.createJsonRpcRequest("test", 1, "hi");
		System.out.println(req.toString(3));
		assertEquals("test", req.get("method"));
		assertEquals(0, req.get("id"));
		assertEquals("1.1", req.get("version"));
		assertEquals(1, req.getJSONArray("params").getInt(0));
		assertEquals("hi", req.getJSONArray("params").getString(1));
	}
	
	public void testRequestFactory2() throws JSONException {
		ArrayList<JsonBean> temp = new ArrayList<JsonBean>();
		temp.add(new JsonBean());
		temp.add(new JsonBean());
		temp.get(0).setTest("hi");
		temp.get(1).setTest("there");
		JSONObject req = JsonRpcRequestFactory.createJsonRpcRequest("test", temp);
		System.out.println(req.toString(3));
		assertEquals("test", req.get("method"));
		assertEquals(0, req.get("id"));
		assertEquals("1.1", req.get("version"));
		assertNotNull(req.getJSONArray("params").getJSONArray(0));
		assertNotNull(req.getJSONArray("params").getJSONArray(0).getJSONObject(0));
		assertNotNull(req.getJSONArray("params").getJSONArray(0).getJSONObject(1));
		assertEquals("hi", req.getJSONArray("params").getJSONArray(0).getJSONObject(0).getString("test"));
		assertEquals("there", req.getJSONArray("params").getJSONArray(0).getJSONObject(1).getString("test"));
	}
	
	public void testToJson() throws JSONException {
		System.out.println("testToJson()");
		List<String> testList = new ArrayList<String>();
		System.out.println("bean:" + testList.getClass().getSimpleName());
		// test empty list
		Object output = BeanToJsonSerializer.serialize(testList);
		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		System.out.println();
		String serialized = BeanToJsonSerializer.serializeToJsonObject(testList).toString();
		System.out.println(serialized);
		assertEquals(serialized, "{\"array\":[]}");
		System.out.println("--- END testToJson()");
	}
	
	public void testToJson2() throws JSONException {
		System.out.println("testToJson2()");
		List<String> testList = new ArrayList<String>();
		testList.add("blah");
		System.out.println("bean:" + testList.getClass().getSimpleName());
		Object output = BeanToJsonSerializer.serialize(testList);
		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		assertEquals(jsonOut.toString(), "{\"result\":[\"blah\"]}");
		System.out.println(jsonOut.toString());
		System.out.println();
		String serialized = BeanToJsonSerializer.serializeToJsonObject(testList).toString();
		System.out.println(serialized);
		assertEquals(serialized, "{\"array\":[\"blah\"]}");
		
		System.out.println("--- END testToJson2()");
	}
	
	public void testToJson3() throws JSONException {
		System.out.println("testToJson3()");
		JsonBean testBean = new JsonBean();
		testBean.setTest("ahold");
		testBean.setTestType(TEST_TYPE.testing);
		testBean.setTestStrings(Arrays.asList(new String[] {"something", "else"} ));
		System.out.println("bean:" + testBean.getClass().getSimpleName());
		Object output = BeanToJsonSerializer.serialize(testBean);
		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		System.out.println();
		System.out.println(BeanToJsonSerializer.serializeToJsonObject(testBean));
		System.out.println("--- END testToJson3()");
	}
	
	public void testToJson4() throws JSONException {
		System.out.println("testToJson4()");
		String[] input = new String[] { "blah" };
		
		Object output = BeanToJsonSerializer.serialize(input);
		System.out.println("bean:" + input.getClass().getSimpleName());

		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		System.out.println(BeanToJsonSerializer.serialize(input).toString());
		System.out.println(BeanToJsonSerializer.serializeToJsonObject(input));
		System.out.println("--- END testToJson4()");
	}
	
	public void testToJson5() throws JSONException {
		System.out.println("testToJson5()");
		String input = new String("blah");
		
		Object output = BeanToJsonSerializer.serialize(input);
		System.out.println("bean:" + input.getClass().getSimpleName());

		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		assertEquals(jsonOut.toString(), "{\"result\":\"" + input + "\"}");
		System.out.println();
		System.out.println(BeanToJsonSerializer.serialize(input));
		System.out.println(BeanToJsonSerializer.serializeToJsonObject(input));
		assertEquals(BeanToJsonSerializer.serializeToJsonObject(input).toString(), "{\"String\":\"" + input + "\"}");
		System.out.println("--- END testToJson5()");
	}

	public void testToJson6() throws JSONException {
		System.out.println("testToJson6()");
		DatatypeFactory dtFactory = null;
		try {
			dtFactory = DatatypeFactory.newInstance();
		} catch (DatatypeConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		XMLGregorianCalendar cal = dtFactory.newXMLGregorianCalendar((int)2006, 
				01, 01, 11,01, 02, 00, DatatypeConstants.FIELD_UNDEFINED);
		
		Object output = BeanToJsonSerializer.serialize(cal);
		System.out.println("bean:" + cal.getClass().getSimpleName());

		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		assertEquals(jsonOut.toString(), "{\"result\":\"2006-01-01T11:01:02.000\"}");
		System.out.println();
		System.out.println(BeanToJsonSerializer.serializeToJsonObject(cal));
		//assertEquals(BeanToJsonSerializer.serializeToJsonObject(cal).toString(), "{\"String\":\"blah\"}");
		System.out.println("--- END testToJson6()");
	}
	
	public void testToJson7() throws JSONException {
		System.out.println("testToJson7()");
		BigDecimal input = new BigDecimal(3.3);
		System.out.println("input = " + input.toString());
		Object output = BeanToJsonSerializer.serialize(input);
		System.out.println("bean:" + input.getClass().getSimpleName());

		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		assertEquals(jsonOut.toString(), "{\"result\":" + input.toString() + "}");
		System.out.println();
		System.out.println(BeanToJsonSerializer.serialize(input));
		System.out.println(BeanToJsonSerializer.serializeToJsonObject(input));
		assertEquals(BeanToJsonSerializer.serializeToJsonObject(input).toString(), "{\"BigDecimal\":" + input.toString() + "}");
		System.out.println("--- END testToJson7()");
	}
	
	public void testToJson8() throws JSONException {
		System.out.println("testToJson8()");
		
		Object output = BeanToJsonSerializer.serializeToJsonObject(new BigDecimal(3.3));
		Object reserialize = BeanToJsonSerializer.serialize(output);
		
		System.out.println(output.toString());
		System.out.println(reserialize.toString());
		
		assertEquals(output, reserialize);
		
		Object reserialize2 = BeanToJsonSerializer.serialize(JSONNull.getInstance());
		
		assertTrue(JSONUtils.isNull(reserialize2));
		
		System.out.println("--- END testToJson8()");
	}
	
	
	public void testToJson9() throws JSONException {
		System.out.println("testToJson9()");
		SortedMap<String, JsonBean2> testIt = new TreeMap<String, JsonBean2>();
		JsonBean2 bean = new JsonBean2();
		bean.setTestBoolean(false);
		testIt.put("testing", bean);
		bean.setTestBoolean(true);
		testIt.put("second", bean);
		Object output = BeanToJsonSerializer.serializeToJsonObject(testIt);
		Object reserialize = BeanToJsonSerializer.serialize(output);
		
		System.out.println(output.toString());
		System.out.println();
		System.out.println(reserialize.toString());
		
		assertEquals(output, reserialize);
			
		assertEquals(JSONObject.fromObject("{\"second\":{\"testBoolean\":true},\"testing\":{\"testBoolean\":true}}"), output);
		
		Object reserialize2 = BeanToJsonSerializer.serialize(JSONNull.getInstance());
		
		assertTrue(JSONUtils.isNull(reserialize2));
		
		System.out.println("--- END testToJson9()");
	}
	
	public void testToJson10() throws JSONException {
		System.out.println("testToJson10()");
		JsonBean bean = new JsonBean();
		bean.setTestType(null);
		Object output = BeanToJsonSerializer.serializeToJsonObject(bean);
		Object reserialize = BeanToJsonSerializer.serialize(output);
		
		System.out.println(output.toString());
		System.out.println();
		System.out.println(reserialize.toString());
		
		assertEquals(output, reserialize);
		JSONObject expected = JSONObject.fromObject("{\"testStrings\":null,\"testJsonBean2\":null,\"testDbl\":null,\"testLng\":null,\"testType\":null,\"testJsonBean2Array\":null,\"test\":\"\"}");
		JSONAssert.assertEquals(expected, output);
		
		Object reserialize2 = BeanToJsonSerializer.serialize(JSONNull.getInstance());
		
		assertTrue(JSONUtils.isNull(reserialize2));
		
		System.out.println("--- END testToJson10()");
	}
	
	private Date testDate = null;
	private Date testSqlDate = null;
	
	public class InvocationTest { 
		public boolean testDate(Date in) { 
			//System.out.println("in = " + in + " vs test = " + testDate);
			return in.equals(testDate);
		}
		
		public boolean testSqlDate(java.sql.Date in) { 
			//System.out.println("in = " + in + " vs test = " + testSqlDate);
			//System.out.println("in=" + in.getTime());
			return in.compareTo(testSqlDate) == 0;
		}
	}
	
	public void testToJson11() throws JSONException, DatatypeConfigurationException {
		System.out.println("testToJson11()");
		Date bean = new Date();
		testDate = bean;
		
		GregorianCalendar inGregorian = new GregorianCalendar();
		XMLGregorianCalendar tmp = DatatypeFactory.newInstance().newXMLGregorianCalendar(inGregorian);
		assertEquals(0, tmp.toGregorianCalendar().compareTo(inGregorian));
		assertEquals(inGregorian.getTime(), tmp.toGregorianCalendar().getTime());
		
		XMLGregorianCalendar xmlTmp = DateConverter.toXMLGregorianCalendar(tmp.toGregorianCalendar().getTime());
		assertEquals(tmp.toString(), xmlTmp.toString());
		
		Object output = BeanToJsonSerializer.serializeToJsonObject(bean);
		Object reserialize = BeanToJsonSerializer.serialize(output);
		
		System.out.println(output.toString());
		System.out.println();
		System.out.println(reserialize.toString());
		
		assertEquals(output, reserialize);
		//assertEquals(output.toString(), "{\"testStrings\":null,\"testJsonBean2\":null,\"testDbl\":null,\"testLng\":null,\"testType\":null,\"testJsonBean2Array\":null,\"test\":\"\"}");
		
		
		JsonRpcOperationInvoker invoker = new JsonRpcOperationInvoker(new JsonRpcService(new InvocationTest()));
		JSONArray params = new JSONArray(); 
		params.add(((JSONObject)output));
		
		try {
			Object result = invoker.invokeMethod("testDate", params, null);
			//System.out.println("result = " + result);
			assertTrue((Boolean)result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			JSONArray params2 = new JSONArray(); 
			params2.add("{\"Date\":\"" + bean.toString() + "\"}");
			testDate = new Date(testDate.toString());
			Object result = invoker.invokeMethod("testDate", params2, null);
			assertTrue((Boolean)result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			JSONArray params3 = new JSONArray(); 
			params3.add("{\"Date\":\"" + (new java.sql.Date(bean.getTime())).toString() + "\"}");
			Object result = invoker.invokeMethod("testDate", params3, null);
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			testSqlDate = (java.sql.Date.valueOf(format.format(bean)));
			Object result2 = invoker.invokeMethod("testSqlDate", params3, null);
			assertTrue((Boolean)result2);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("--- END testToJson11()");
	}
	
	public void testToJson12() throws JSONException {
		System.out.println("testToJson12()");
		List<String> test = new ArrayList<String>() {{
			add("blah");
		}};
		
		Object output = BeanToJsonSerializer.serialize(test);
		
		JSONObject jsonOut = new JSONObject();
		jsonOut.put("result", output);
		System.out.println(jsonOut.toString());
		System.out.println(BeanToJsonSerializer.serialize(test).toString());
		System.out.println(BeanToJsonSerializer.serializeToJsonObject(test));
		System.out.println("--- END testToJson12()");
	}
}
